package com.lihang.rabbit1.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 日志拦截器，记录请求参数
 */
@Slf4j
@Component
public class LoggingInterceptor implements HandlerInterceptor {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        try {
            String requestURI = request.getRequestURI();
            String method = request.getMethod();
            String contentType = request.getContentType();
        //    String traceId = TraceContext.getTraceId(); // 获取traceId

            Map<String, Object> allParams = new HashMap<>();

            // 1. 记录URL查询参数
            Map<String, String> queryParams = new HashMap<>();
            Enumeration<String> parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                String name = parameterNames.nextElement();
                String value = request.getParameter(name);
                queryParams.put(name, value);
            }
            if (!queryParams.isEmpty()) {
                allParams.put("查询参数", queryParams);
            }

            // 2. 记录请求头参数
            Map<String, String> headers = new HashMap<>();
            Enumeration<String> headerNames = request.getHeaderNames();
            if (headerNames != null) {
                while (headerNames.hasMoreElements()) {
                    String headerName = headerNames.nextElement();
                    // 排除一些常见的大型头，以免日志过大
                    if (!headerName.equalsIgnoreCase("Authorization") &&
                            !headerName.equalsIgnoreCase("Cookie")) {
                        headers.put(headerName, request.getHeader(headerName));
                    }
                }
            }
            if (!headers.isEmpty()) {
                allParams.put("请求头", headers);
            }

            // 3. 记录Cookie参数
            Cookie[] cookies = request.getCookies();
            if (cookies != null && cookies.length > 0) {
                Map<String, String> cookieMap = Arrays.stream(cookies)
                        .collect(Collectors.toMap(
                                Cookie::getName,
                                Cookie::getValue,
                                (v1, v2) -> v1));
                allParams.put("Cookie", cookieMap);
            }

            // 4. 记录请求体内容（如果有）
            Object requestBody = request.getAttribute("requestBody");
            if (requestBody != null) {
                String body = requestBody.toString();

                // 处理不同类型的请求体
                if (contentType != null) {
                    if (contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
                        // JSON请求，直接解析为对象放入
                        try {
                            // 直接将JSON字符串解析为对象，保留原始结构
                            Object jsonObj = objectMapper.readValue(body, Object.class);
                            // 将解析后的对象直接放入参数Map，而不是字符串形式
                            allParams.put("JSON请求体", jsonObj);
                        } catch (Exception e) {
                            allParams.put("JSON请求体(解析失败)", body);
                        }
                    } else if (contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
                        // 表单数据已经在queryParams中包含，不需要重复记录
                        allParams.put("表单数据", "已包含在查询参数中");
                    } else if (contentType.contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {
                        // 多部分表单数据，通常包含文件
                        allParams.put("多部分表单", "包含文件上传，大小过大不记录具体内容");
                    } else {
                        // 其他类型的请求体
                        allParams.put("其他请求体", body);
                    }
                }
            }

            // 5. 记录路径变量信息(如果有HandlerMapping信息)
            Object pathVariables = request
                    .getAttribute("org.springframework.web.servlet.HandlerMapping.uriTemplateVariables");
            if (pathVariables != null) {
                allParams.put("路径变量", pathVariables);
            }

            // 记录完整的请求日志，直接传递对象让日志系统处理格式化
            // 这样可以避免双重转义的问题
            log.info("请求URI: {}, 请求方法: {}, 内容类型: {}, 参数: {}",
                     requestURI, method, contentType, allParams);
        } catch (Exception e) {
            log.error("记录请求日志时发生错误", e);
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) {
        // 请求处理后的逻辑
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        // 记录响应状态码
      //  String traceId = TraceContext.getTraceId(); // 获取traceId
        log.info(" 请求URI: {}, 响应状态: {}",  request.getRequestURI(), response.getStatus());
    }
}